// Copyright (c) 2009 Mike Haight, Andy Kipp
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.


#include "Texture.h"

using namespace HandBanana::Core;

extern boost::shared_ptr<Engine> gEngine;

Texture::Texture(const std::wstring& argName, int argWidth, int argHeight, int argFrameWidth, int argFrameHeight) : mName(argName), mWidth(argWidth), mHeight(argHeight), mFrameWidth(argFrameWidth), mFrameHeight(argFrameHeight)
{
    // Make sure the texture parameters are valid
    if (mWidth % mFrameWidth)
        throw std::exception("The texture width must be evenly divisible by the frame width");

    if (mHeight % mFrameHeight)
        throw std::exception("The texture height must be evenly divisible by the frame height");

    mFramesPerRow = mWidth / mFrameWidth;
    mFloatFrameWidth = mFrameWidth / (float)mWidth;
    mFloatFrameHeight = mFrameHeight / (float)mHeight;
}


Texture::~Texture(void)
{
    if (mReferenceCount)
    {
        //smLogger->Warn("{0} outstanding references to texture pointer '{1}'", mReferenceCount, mName);
        SAFE_RELEASE(mTexturePointer);
    }
}


std::wstring Texture::Name(void) const
{
    return mName;
}


int Texture::Height(void) const
{
    return mHeight;
}


int Texture::Width(void) const
{
    return mWidth;
}


IUnknown* Texture::TexturePointer(void) const
{
    return mTexturePointer;
}


int Texture::FrameHeight(void) const
{
    return mFrameHeight;
}


int Texture::FrameWidth(void) const
{
    return mFrameWidth;
}


void Texture::AddReference(void)
{
    if (!(mReferenceCount++))
    {
        mTexturePointer = gEngine->GetRenderer()->CreateTexture(boost::str(boost::wformat(L"data/texture/%1%.png") % mName));
    }
}


void Texture::Release(void)
{
    if (!(--mReferenceCount))
    {
        SAFE_RELEASE(mTexturePointer);
    }
}


Frame Texture::GetFrame(int argFrameId) const
{
    if (argFrameId < 0)
        throw std::invalid_argument("Frame Id must be greater than or equal to zero");

    return Frame(
        argFrameId,
        mFloatFrameWidth * (argFrameId % mFramesPerRow),
        mFloatFrameHeight * (argFrameId / mFramesPerRow),
        mFloatFrameWidth,
        mFloatFrameHeight);
}


void Texture::ReadXml(const XmlReader& argReader)
{
    XmlDocument doc;

    // Load the XML document and get the document element
    doc.Load(argReader);
    XmlElement* textureElement = doc.GetDocumentElement();

    // Get texture attributes
    mName = textureElement->GetAttribute(L"name")->GetValue();
    mWidth = boost::lexical_cast<int>(textureElement->GetAttribute(L"width")->GetValue());
    mHeight = boost::lexical_cast<int>(textureElement->GetAttribute(L"height")->GetValue());
    mFrameWidth = boost::lexical_cast<int>(textureElement->GetAttribute(L"frameWidth")->GetValue());
    mFrameHeight = boost::lexical_cast<int>(textureElement->GetAttribute(L"frameHeight")->GetValue());

    // Make sure the texture parameters are valid
    THROW_IF_FALSE(!(mWidth % mFrameWidth), "The texture width must be evenly divisible by the frame width");
    THROW_IF_FALSE(!(mHeight % mFrameHeight), "The texture height must be evenly divisible by the frame height");

    mFramesPerRow = mWidth / mFrameWidth;
    mFloatFrameWidth = mFrameWidth / (float)mWidth;
    mFloatFrameHeight = mFrameHeight / (float)mHeight;
}


void Texture::WriteXml(const XmlWriter& argWriter)
{
    throw std::exception("Function not implemented");
}
